package com.cehome.cloudbox.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.cehome.cloudbox.constans.Constants;
import com.cehome.cloudbox.constans.PlConstants;
import com.cehome.cloudbox.doman.vo.ProDefExtemdInfo;
import com.cehome.cloudbox.doman.vo.ProcDefExtendQueryVo;
import com.cehome.cloudbox.doman.vo.ProcDefExtendShowVo;
import com.cehome.cloudbox.doman.vo.TaskInfo;
import com.cehome.cloudbox.entity.ProcDefExtend;
import com.cehome.cloudbox.flowalbe.FlowableTaskService;
import com.cehome.cloudbox.mapper.ProcDefExtendMapper;
import com.cehome.cloudbox.service.IProcDefExtendService;
import com.cehome.cloudbox.utils.FlowAbleUtil;
import com.cehome.cloudbox.utils.UUidUtil;
import org.flowable.bpmn.BpmnAutoLayout;
import org.flowable.bpmn.converter.BpmnXMLConverter;
import org.flowable.bpmn.model.*;
import org.flowable.bpmn.model.Process;
import org.flowable.engine.ProcessEngine;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.TaskService;
import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.validation.ProcessValidator;
import org.flowable.validation.ProcessValidatorFactory;
import org.flowable.validation.ValidationError;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import javax.annotation.Resource;
import java.io.InputStream;
import java.util.*;
import java.util.stream.Collectors;
import org.flowable.task.api.Task;

/**
 * <p>
 * 流程定义扩展表 服务实现类
 * </p>
 * @author zfl
 */
@Service
public class ProcDefExtendServiceImpl extends ServiceImpl<ProcDefExtendMapper, ProcDefExtend> implements IProcDefExtendService {

    @Resource
    protected RepositoryService repositoryService;

    @Resource
    ProcessEngine processEngine;

    @Resource
    private TaskService taskService;

    /**
     * 分页查询
     *
     * @param queryVo 流程定义扩展查询接口Vo
     * @return 流程定义扩展
     */
    @Override
    public Page<ProcDefExtendShowVo> page(ProcDefExtendQueryVo queryVo) {
        // 获取分页数据
        LambdaQueryWrapper<ProcDefExtend> lambdaQueryWrapper = Wrappers.lambdaQuery();
        lambdaQueryWrapper
                .select(ProcDefExtend::getId,
                        ProcDefExtend::getProcDefId,
                        ProcDefExtend::getProcDefCode,
                        ProcDefExtend::getOrg,
                        ProcDefExtend::getType,
                        ProcDefExtend::getStatus,
                        ProcDefExtend::getUpdateTime)
                .like(StrUtil.isNotEmpty(queryVo.getProcDefCode()), ProcDefExtend::getProcDefCode, queryVo.getProcDefCode())
                .like(StrUtil.isNotEmpty(queryVo.getName()), ProcDefExtend::getName, queryVo.getName())
                .orderByDesc(ProcDefExtend::getUpdateTime);
        Page<ProcDefExtend> procDefExtendPage = page(new Page<>(queryVo.getCurrent(), queryVo.getPageSize()), lambdaQueryWrapper);
        List<ProcDefExtend> procDefExtendList = procDefExtendPage.getRecords();
        if (ObjectUtil.isEmpty(procDefExtendList)) {
            return new Page<>();
        }

        // 流程定义ID集合
        Set<String> procDefIdSet = procDefExtendList.stream()
                .map(ProcDefExtend::getProcDefId).filter(StrUtil::isNotEmpty).collect(Collectors.toSet());
        List<ProcessDefinition> processDefinitionList = new ArrayList<>();
        Map<String, Date> deploymentTimeMap = new HashMap<>();
        if (ObjectUtil.isNotEmpty(procDefIdSet)) {
            // 根据流程定义集合获取最后版本
            processDefinitionList = repositoryService.createProcessDefinitionQuery()
                    .processDefinitionIds(procDefIdSet)
                    .latestVersion()
                    .list();
            List<String> deploymentIdList = processDefinitionList.stream().map(ProcessDefinition::getDeploymentId).collect(Collectors.toList());

            // 获取部署信息
            List<Deployment> deploymentList = repositoryService.createDeploymentQuery()
                    .deploymentIds(deploymentIdList).list();
            deploymentTimeMap = deploymentList.stream().collect(Collectors.toMap(Deployment::getId, Deployment::getDeploymentTime));
        }

        // 编辑版本
        List<ProcDefExtendShowVo> procDefExtendShowVoList = new ArrayList<>();
        ProcDefExtendShowVo procDefExtendShowVo;
        for (ProcDefExtend procDefExtend : procDefExtendList) {
            procDefExtendShowVo = new ProcDefExtendShowVo();
            BeanUtil.copyProperties(procDefExtend, procDefExtendShowVo);
            if (StrUtil.isEmpty(procDefExtend.getProcDefId())) {
                procDefExtendShowVoList.add(procDefExtendShowVo);
                continue;
            }

            for (ProcessDefinition processDefinition : processDefinitionList) {
                if (procDefExtend.getProcDefId().equals(processDefinition.getId())) {
                    // 设定版本
                    procDefExtendShowVo.setVersion(processDefinition.getVersion());
                    // 发布时间
                    procDefExtendShowVo.setDeploymentTime(deploymentTimeMap.get(processDefinition.getDeploymentId()));
                    break;
                }
            }
            procDefExtendShowVoList.add(procDefExtendShowVo);
        }

        Page<ProcDefExtendShowVo> procDefExtendShowVoPage = new Page<>(
                procDefExtendPage.getCurrent(), procDefExtendPage.getPages(), procDefExtendPage.getTotal());
        procDefExtendShowVoPage.setRecords(procDefExtendShowVoList);
        return procDefExtendShowVoPage;
    }

    /**
     * 已发布分页查询
     *
     * @param queryVo 流程定义扩展查询接口Vo
     * @return 流程定义扩展
     */
    @Override
    public Page<ProcDefExtendShowVo> selectFlowAblePage(ProcDefExtendQueryVo queryVo) {
        // 获取分页数据
        LambdaQueryWrapper<ProcDefExtend> lambdaQueryWrapper = Wrappers.lambdaQuery();
        lambdaQueryWrapper
                .select(ProcDefExtend::getId,
                        ProcDefExtend::getProcDefId,
                        ProcDefExtend::getProcDefCode,
                        ProcDefExtend::getStatus,
                        ProcDefExtend::getOrg,
                        ProcDefExtend::getType,
                        ProcDefExtend::getUpdateTime)
                .isNotNull(ProcDefExtend::getProcDefId)
                .like(StrUtil.isNotEmpty(queryVo.getProcDefCode()), ProcDefExtend::getProcDefCode, queryVo.getProcDefCode())
                .like(StrUtil.isNotEmpty(queryVo.getName()), ProcDefExtend::getName, queryVo.getName())
                .orderByDesc(ProcDefExtend::getUpdateTime);
        Page<ProcDefExtend> procDefExtendPage = page(new Page<>(queryVo.getCurrent(), queryVo.getPageSize()), lambdaQueryWrapper);
        List<ProcDefExtend> procDefExtendList = procDefExtendPage.getRecords();
        if (ObjectUtil.isEmpty(procDefExtendList)) {
            return new Page<>();
        }

        // 流程定义ID集合
        Set<String> procDefIdSet = procDefExtendList.stream()
                .map(ProcDefExtend::getProcDefId).filter(StrUtil::isNotEmpty).collect(Collectors.toSet());
        List<ProcessDefinition> processDefinitionList = new ArrayList<>();
        Map<String, Date> deploymentTimeMap = new HashMap<>();
        if (ObjectUtil.isNotEmpty(procDefIdSet)) {
            // 根据流程定义集合获取最后版本
            processDefinitionList = repositoryService.createProcessDefinitionQuery()
                    .processDefinitionIds(procDefIdSet)
                    .latestVersion()
                    .list();
            List<String> deploymentIdList = processDefinitionList.stream().map(ProcessDefinition::getDeploymentId).collect(Collectors.toList());

            // 获取部署信息
            List<Deployment> deploymentList = repositoryService.createDeploymentQuery()
                    .deploymentIds(deploymentIdList).list();
            deploymentTimeMap = deploymentList.stream().collect(Collectors.toMap(Deployment::getId, Deployment::getDeploymentTime));
        }

        // 编辑版本
        List<ProcDefExtendShowVo> procDefExtendShowVoList = new ArrayList<>();
        ProcDefExtendShowVo procDefExtendShowVo;
        for (ProcDefExtend procDefExtend : procDefExtendList) {
            procDefExtendShowVo = new ProcDefExtendShowVo();
            BeanUtil.copyProperties(procDefExtend, procDefExtendShowVo);
            if (StrUtil.isEmpty(procDefExtend.getProcDefId())) {
                procDefExtendShowVoList.add(procDefExtendShowVo);
                continue;
            }

            for (ProcessDefinition processDefinition : processDefinitionList) {
                if (procDefExtend.getProcDefId().equals(processDefinition.getId())) {
                    // 设定版本
                    procDefExtendShowVo.setVersion(processDefinition.getVersion());
                    // 发布时间
                    procDefExtendShowVo.setDeploymentTime(deploymentTimeMap.get(processDefinition.getDeploymentId()));
                    break;
                }
            }
            procDefExtendShowVoList.add(procDefExtendShowVo);
        }

        Page<ProcDefExtendShowVo> procDefExtendShowVoPage = new Page<>(
                procDefExtendPage.getCurrent(), procDefExtendPage.getPages(), procDefExtendPage.getTotal());
        procDefExtendShowVoPage.setRecords(procDefExtendShowVoList);
        return procDefExtendShowVoPage;
    }

    /**
     * 删除流程定义扩展表
     *
     * @param id 流程定义扩展ID
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(Long id) {
        ProcDefExtend procDefExtend = baseMapper.selectById(id);

        // 删除流程定义扩展表
        baseMapper.deleteById(id);

        if (StrUtil.isNotEmpty(procDefExtend.getProcDefId())) {
            // 获取流程定义
            ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                    .processDefinitionId(procDefExtend.getProcDefId())
                    .singleResult();
            // true 允许级联删除 ,不设置会导致数据库外键关联异常
            repositoryService.deleteDeployment(processDefinition.getDeploymentId(), true);
        }
    }

    /**
     * 发布流程定义扩展表
     *
     * @param id 流程定义扩展ID
     */
    @Override
    public void deploy(Long id) {
        ProcDefExtend procDefExtend = baseMapper.selectById(id);

        // 发布
        Deployment deploy = repositoryService.createDeployment()
                .addString(procDefExtend.getProcDefCode() + PlConstants.BPMN_FILE_SUFFIX, procDefExtend.getBpmnXml())
                .name(procDefExtend.getName())
                .deploy();
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .deploymentId(deploy.getId())
                .processDefinitionKey(procDefExtend.getProcDefCode())
                .singleResult();

        // 更新流程定义ID
        LambdaUpdateWrapper<ProcDefExtend> updateWrapper = Wrappers.lambdaUpdate();
        updateWrapper
                .set(ProcDefExtend::getProcDefId, processDefinition.getId())
                .eq(ProcDefExtend::getId, id);
        baseMapper.update(null, updateWrapper);
    }
    @Override
    public boolean updateProcDefExtend(ProDefExtemdInfo defExtemdInfo){
        Deployment deploy=null;
        List<TaskInfo> list = defExtemdInfo.getList();
        TaskInfo first = new TaskInfo();
        first.setAssgins("11");
        first.setChaosongs("2");
        first.setHuiqian(false);
        first.setRaido(true);
        first.setZhihui(false);
        first.setTaskName("审批1");
        list.add(0,first);
        defExtemdInfo.setList(list);
        BpmnModel bpmnModel=new BpmnModel();
        String procDefCode="process_"+ UUidUtil.getUUID();
        Process process = FlowAbleUtil.createProcess(defExtemdInfo.getList(),procDefCode);
        bpmnModel.addProcess(process);

        //校验bpmModel
        ProcessValidator processValidator=new ProcessValidatorFactory().createDefaultProcessValidator();
        List<ValidationError> validationErrorList=processValidator.validate(bpmnModel);
        if (validationErrorList.size()>0){
            throw new RuntimeException("流程有误，请检查后重试");
        }
        //生成自动布局
        new BpmnAutoLayout(bpmnModel).execute();
        deploy =repositoryService.createDeployment().addBpmnModel(procDefCode+ PlConstants.BPMN_FILE_SUFFIX,bpmnModel).deploy();
        boolean flag=false;
        if(null!=deploy){
            ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                    .deploymentId(deploy.getId())
                    .processDefinitionKey(procDefCode)
                    .singleResult();
            LambdaQueryWrapper<ProcDefExtend> lambdaQueryWrap = new LambdaQueryWrapper<ProcDefExtend>();
            lambdaQueryWrap.eq(ProcDefExtend::getOrg,defExtemdInfo.getOrg()).eq(ProcDefExtend::getType,defExtemdInfo.getType());
            ProcDefExtend procDefExtend = this.getOne(lambdaQueryWrap);
            this.delete(procDefExtend.getId());
            procDefExtend = new ProcDefExtend();

            TaskInfo info = defExtemdInfo.getList().get(0);
            procDefExtend.setFirstZhihui(info.isZhihui()+"");
            procDefExtend.setFirstZhihuiPersons(info.getChaosongs());

            procDefExtend.setFirstHuiqian(info.isHuiqian()+"");
            procDefExtend.setFirstHuiqianPersons(info.getAssgins());

            procDefExtend.setOrg(defExtemdInfo.getOrg());
            procDefExtend.setType(defExtemdInfo.getType());
            procDefExtend.setProcDefId(processDefinition.getId());
            procDefExtend.setProcDefCode(procDefCode);
            BpmnXMLConverter bpmnXMLConverter=new BpmnXMLConverter();
            String bpmn=new String(bpmnXMLConverter.convertToXML(bpmnModel));
            System.out.println(bpmn);
            procDefExtend.setBpmnXml(new String(bpmnXMLConverter.convertToXML(bpmnModel)));
            flag= this.save(procDefExtend);
        }
        return flag;
    }

    @Override
    public boolean saveProcDefExtend(ProDefExtemdInfo defExtemdInfo) {
        boolean flag=false;
        LambdaQueryWrapper<ProcDefExtend> procDefExtendQueryWrapper = Wrappers.lambdaQuery();
        procDefExtendQueryWrapper.eq(ProcDefExtend::getOrg, defExtemdInfo.getOrg());
        procDefExtendQueryWrapper.eq(ProcDefExtend::getType, defExtemdInfo.getType());
        ProcDefExtend procDefExtend = this.getOne(procDefExtendQueryWrapper);
        if(null== procDefExtend){
            BpmnModel bpmnModel=new BpmnModel();
            String procDefCode="process_"+UUidUtil.getUUID();
            List<TaskInfo> list = defExtemdInfo.getList();
            TaskInfo first = new TaskInfo();
            first.setAssgins("11");
            first.setChaosongs("2");
            first.setHuiqian(false);
            first.setRaido(true);
            first.setZhihui(false);
            first.setTaskName("审批1");
            list.add(0,first);
            defExtemdInfo.setList(list);
            Process process = FlowAbleUtil.createProcess(defExtemdInfo.getList(),procDefCode);
            bpmnModel.addProcess(process);

            //校验bpmModel
            ProcessValidator processValidator=new ProcessValidatorFactory().createDefaultProcessValidator();
            List<ValidationError> validationErrorList=processValidator.validate(bpmnModel);
            if (validationErrorList.size()>0){
                throw new RuntimeException("流程有误，请检查后重试");
            }
            //生成自动布局
            new BpmnAutoLayout(bpmnModel).execute();
            String name="";
            if(defExtemdInfo.getType()==0){
                name="机械运转单";
            }
            if(defExtemdInfo.getType()==1){
                name="用工申请单";
            }
            BpmnXMLConverter bpmnXmlConverter=new BpmnXMLConverter();
            String bpmn=new String(bpmnXmlConverter.convertToXML(bpmnModel));
            Deployment deploy = repositoryService.createDeployment().addString(procDefCode + PlConstants.BPMN_FILE_SUFFIX, bpmn).name(name).deploy();
            if(null!=deploy){
                ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                        .deploymentId(deploy.getId())
                        .processDefinitionKey(procDefCode)
                        .singleResult();
                procDefExtend = new ProcDefExtend();
                procDefExtend.setName(name);
                TaskInfo info = defExtemdInfo.getList().get(0);
                procDefExtend.setFirstZhihui(info.isZhihui()+"");
                procDefExtend.setFirstZhihuiPersons(info.getChaosongs());

                procDefExtend.setFirstHuiqian(info.isHuiqian()+"");
                procDefExtend.setFirstHuiqianPersons(info.getAssgins());

                procDefExtend.setOrg(defExtemdInfo.getOrg());
                procDefExtend.setType(defExtemdInfo.getType());
                procDefExtend.setProcDefId(processDefinition.getId());
                procDefExtend.setProcDefCode(procDefCode);
                System.out.println(bpmn);
                procDefExtend.setBpmnXml(bpmn);
                flag= this.save(procDefExtend);
            }
        }
        return flag;
    }


    @Override
    public TaskInfo selectApproveCandidates(ProDefExtemdInfo param) {
        LambdaQueryWrapper<ProcDefExtend> procDefExtendQueryWrapper = Wrappers.lambdaQuery();
        procDefExtendQueryWrapper.eq(ProcDefExtend::getOrg, param.getOrg());
        procDefExtendQueryWrapper.eq(ProcDefExtend::getType, param.getType());
        ProcDefExtend procDefExtend = this.getOne(procDefExtendQueryWrapper);
        //获取全部流程
        BpmnModel bpmnModel = repositoryService.getBpmnModel(procDefExtend.getProcDefId());
        List<Process> processesList = bpmnModel.getProcesses();
        FlowElement flowElement = processesList.get(0).getFlowElement("task_f075096b905642e18caf6bd05acbb8d3");
        Map<String, List<ExtensionElement>> extensionElementMap=flowElement.getExtensionElements();
        TaskInfo taskInfo = new TaskInfo();
        for(String key:extensionElementMap.keySet()){
            List<ExtensionElement> extensionElementList = extensionElementMap.get(key);
            if("shenpi".equals(key)&&!extensionElementList.isEmpty()){
                taskInfo.setAssgins(extensionElementList.get(0).getElementText());
            }
            if("huiqian".equals(key)&&!extensionElementList.isEmpty()){
                taskInfo.setHuiqian("true".equals(extensionElementList.get(0).getElementText()));
            }
            if("zhihui".equals(key)&&!extensionElementList.isEmpty()){
                taskInfo.setZhihui("true".equals(extensionElementList.get(0).getElementText()));
            }
            if("zhihuiPerson".equals(key)&&!extensionElementList.isEmpty()){
                taskInfo.setChaosongs(extensionElementList.get(0).getElementText());
            }
        }
        return taskInfo;
    }


    @Override
    public TaskInfo selectNextApproveCandidates(ProDefExtemdInfo param) {
        LambdaQueryWrapper<ProcDefExtend> procDefExtendQueryWrapper = Wrappers.lambdaQuery();
        procDefExtendQueryWrapper.eq(ProcDefExtend::getOrg, param.getOrg());
        procDefExtendQueryWrapper.eq(ProcDefExtend::getType, param.getType());
        ProcDefExtend procDefExtend = this.getOne(procDefExtendQueryWrapper);
        BpmnModel bpmnModel = processEngine.getRepositoryService().getBpmnModel(procDefExtend.getProcDefId());
        Task task = taskService.createTaskQuery().processInstanceId(procDefExtend.getProcDefId()).active().singleResult();
        ExecutionEntity ee = (ExecutionEntity)this.processEngine.getRuntimeService().createExecutionQuery().executionId(task.getExecutionId()).singleResult();
        // 当前审批节点id
        String crruentActivityId = ee.getActivityId();
        //根据活动节点id获取对应的node
        FlowNode flowNode = (FlowNode) bpmnModel.getFlowElement(crruentActivityId);
        //获取连接线
        List<SequenceFlow> outFlows = flowNode.getOutgoingFlows();
        FlowElement element =null;
        for (SequenceFlow sequenceFlow : outFlows) {
            //当前审批节点
            element = sequenceFlow.getTargetFlowElement();
        }
        System.out.println(element);
        return null;
    }
}
